//
// Created by zerax on 2020/10/26.
//

#pragma once

#include <glad/glad.h>
#include <vector>
#include <glm/glm.hpp>
#include <optional>
#include <tuple>
#include <memory>
#include "utils.hh"

enum class VertexArrayType {
    Static, Dynamic, Streaming
};

class VertexArrayBuilder;

struct VertexArray {
    friend VertexArrayBuilder;
public:
    VertexArray() = default;
    explicit VertexArray(bool hasIndex);
    DELETE_COPY(VertexArray);
    ~VertexArray();

    void draw() const;
private:
    size_t m_vertexCount = 0;
    GLuint m_rawHandle = 0;
    GLuint m_vertexBuffer = 0;
    std::optional<GLuint> m_indexBuffer = std::nullopt;
};

class VertexArrayBuilder {
    using PositionData = std::pair<GLuint, std::vector<glm::vec3>*>;
    using TexCoordData = std::pair<GLuint, std::vector<glm::vec2>*>;
    using NormalData = std::pair<GLuint, std::vector<glm::vec3>>;
    using IndexData = std::vector<GLuint>*;
public:
    VertexArrayBuilder(unsigned int loc, std::vector<glm::vec3>& positions);

    VertexArrayBuilder& withTexCoords(unsigned int location, std::vector<glm::vec2>& texCoords);
    VertexArrayBuilder& withTriangles(std::vector<GLuint>& triangles);
    VertexArrayBuilder& calculateNormal(unsigned int location);

    void reset(VertexArray& vao, VertexArrayType type);
    VertexArray build(VertexArrayType type);
private:
    PositionData m_positions;
    std::optional<TexCoordData> m_texCoords;
    std::optional<NormalData> m_normals;
    std::optional<IndexData> m_triangles;
};
